home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-9.10-netbook-remix-PL.iso / casper / filesystem.squashfs / usr / share / pyshared / deluge / config.py < prev    next >
Encoding:
Python Source  |  2009-06-16  |  9.6 KB  |  312 lines

  1. #
  2. # config.py
  3. #
  4. # Copyright (C) 2008 Andrew Resch <andrewresch@gmail.com>
  5. #
  6. # Deluge is free software.
  7. #
  8. # You may redistribute it and/or modify it under the terms of the
  9. # GNU General Public License, as published by the Free Software
  10. # Foundation; either version 3 of the License, or (at your option)
  11. # any later version.
  12. #
  13. # deluge is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  16. # See the GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with deluge.    If not, write to:
  20. #     The Free Software Foundation, Inc.,
  21. #     51 Franklin Street, Fifth Floor
  22. #     Boston, MA  02110-1301, USA.
  23. #
  24. #    In addition, as a special exception, the copyright holders give
  25. #    permission to link the code of portions of this program with the OpenSSL
  26. #    library.
  27. #    You must obey the GNU General Public License in all respects for all of
  28. #    the code used other than OpenSSL. If you modify file(s) with this
  29. #    exception, you may extend this exception to your version of the file(s),
  30. #    but you are not obligated to do so. If you do not wish to do so, delete
  31. #    this exception statement from your version. If you delete this exception
  32. #    statement from all source files in the program, then also delete it here.
  33. #
  34.  
  35. #
  36.  
  37.  
  38. """
  39. Deluge Config Module
  40. """
  41.  
  42. import cPickle as pickle
  43. import shutil
  44. import os
  45. import gobject
  46. import deluge.common
  47. from deluge.log import LOG as log
  48.  
  49. def prop(func):
  50.     """Function decorator for defining property attributes
  51.  
  52.     The decorated function is expected to return a dictionary
  53.     containing one or more of the following pairs:
  54.         fget - function for getting attribute value
  55.         fset - function for setting attribute value
  56.         fdel - function for deleting attribute
  57.     This can be conveniently constructed by the locals() builtin
  58.     function; see:
  59.     http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/205183
  60.     """
  61.     return property(doc=func.__doc__, **func())
  62.  
  63. class Config(object):
  64.     """
  65.     This class is used to access/create/modify config files
  66.  
  67.     :param filename: the name of the config file
  68.     :param defaults: dictionary of default values
  69.     :param config_dir: the path to the config directory
  70.  
  71.     """
  72.     def __init__(self, filename, defaults=None, config_dir=None):
  73.         self.__config = {}
  74.         self.__set_functions = {}
  75.         self.__change_callback = None
  76.         # This will get set with a gobject.timeout_add whenever a config option
  77.         # is set.
  78.         self.__save_timer = None
  79.  
  80.         if defaults:
  81.             self.__config = defaults
  82.  
  83.         # Load the config from file in the config_dir
  84.         if config_dir:
  85.             self.__config_file = os.path.join(config_dir, filename)
  86.         else:
  87.             self.__config_file = deluge.common.get_default_config_dir(filename)
  88.  
  89.         self.load()
  90.  
  91.     def __setitem__(self, key, value):
  92.         """
  93.         See
  94.         :meth:`set_item`
  95.         """
  96.  
  97.         return self.set_item(key, value)
  98.  
  99.     def set_item(self, key, value):
  100.         """
  101.         Sets item 'key' to 'value' in the config dictionary, but does not allow
  102.         changing the item's type unless it is None
  103.  
  104.         :param key: string, item to change to change
  105.         :param value: the value to change item to, must be same type as what is currently in the config
  106.  
  107.         :raises ValueError: raised when the type of value is not the same as what is currently in the config
  108.  
  109.         **Usage**
  110.  
  111.         >>> config = Config("test.conf")
  112.         >>> config["test"] = 5
  113.         >>> config["test"]
  114.         5
  115.  
  116.         """
  117.         if not self.__config.has_key(key):
  118.             self.__config[key] = value
  119.             log.debug("Setting '%s' to %s of %s", key, value, type(value))
  120.             return
  121.  
  122.         if self.__config[key] == value:
  123.             return
  124.  
  125.         # Do not allow the type to change unless it is None
  126.         oldtype, newtype = type(self.__config[key]), type(value)
  127.  
  128.         if value is not None and oldtype != type(None) and oldtype != newtype:
  129.             try:
  130.                 value = oldtype(value)
  131.             except ValueError:
  132.                 log.warning("Type '%s' invalid for '%s'", newtype, key)
  133.                 raise
  134.  
  135.         log.debug("Setting '%s' to %s of %s", key, value, type(value))
  136.  
  137.         self.__config[key] = value
  138.         # Run the set_function for this key if any
  139.         try:
  140.             gobject.idle_add(self.__set_functions[key], key, value)
  141.         except KeyError:
  142.             pass
  143.         try:
  144.             gobject.idle_add(self.__change_callback, key, value)
  145.         except:
  146.             pass
  147.  
  148.         # We set the save_timer for 5 seconds if not already set
  149.         if not self.__save_timer:
  150.             self.__save_timer = gobject.timeout_add(5000, self.save)
  151.  
  152.     def __getitem__(self, key):
  153.         """
  154.         See
  155.         :meth:`get_item`
  156.         """
  157.         return self.get_item(key)
  158.  
  159.     def get_item(self, key):
  160.         """
  161.         Gets the value of item 'key'
  162.  
  163.         :param key: the item for which you want it's value
  164.         :return: the value of item 'key'
  165.  
  166.         :raises KeyError: if 'key' is not in the config dictionary
  167.  
  168.         **Usage**
  169.  
  170.         >>> config = Config("test.conf", defaults={"test": 5})
  171.         >>> config["test"]
  172.         5
  173.  
  174.         """
  175.         return self.__config[key]
  176.  
  177.     def register_change_callback(self, callback):
  178.         """
  179.         Registers a callback function that will be called when a value is changed in the config dictionary
  180.  
  181.         :param callback: the function, callback(key, value)
  182.  
  183.         **Usage**
  184.  
  185.         >>> config = Config("test.conf", defaults={"test": 5})
  186.         >>> def cb(key, value):
  187.         ...     print key, value
  188.         ...
  189.         >>> config.register_change_callback(cb)
  190.  
  191.         """
  192.         self.__change_callback = callback
  193.  
  194.     def register_set_function(self, key, function, apply_now=True):
  195.         """
  196.         Register a function to be called when a config value changes
  197.  
  198.         :param key: the item to monitor for change
  199.         :param function: the function to call when the value changes, f(key, value)
  200.         :keyword apply_now: if True, the function will be called after it's registered
  201.  
  202.         **Usage**
  203.  
  204.         >>> config = Config("test.conf", defaults={"test": 5})
  205.         >>> def cb(key, value):
  206.         ...     print key, value
  207.         ...
  208.         >>> config.register_set_function("test", cb, apply_now=True)
  209.         test 5
  210.  
  211.         """
  212.         log.debug("Registering function for %s key..", key)
  213.         self.__set_functions[key] = function
  214.         # Run the function now if apply_now is set
  215.         if apply_now:
  216.             self.__set_functions[key](key, self.__config[key])
  217.         return
  218.  
  219.     def apply_all(self):
  220.         """
  221.         Calls all set functions
  222.  
  223.         **Usage**
  224.  
  225.         >>> config = Config("test.conf", defaults={"test": 5})
  226.         >>> def cb(key, value):
  227.         ...     print key, value
  228.         ...
  229.         >>> config.register_set_function("test", cb, apply_now=False)
  230.         >>> config.apply_all()
  231.         test 5
  232.  
  233.         """
  234.         log.debug("Calling all set functions..")
  235.         for key, value in self.__set_functions.iteritems():
  236.             value(key, self.__config[key])
  237.  
  238.     def load(self, filename=None):
  239.         """
  240.         Load a config file
  241.  
  242.         :param filename: if None, uses filename set in object initialization
  243.  
  244.  
  245.         """
  246.         if not filename:
  247.             filename = self.__config_file
  248.         try:
  249.             self.__config.update(pickle.load(open(filename, "rb")))
  250.         except Exception, e:
  251.             log.warning("Unable to load config file: %s", filename)
  252.  
  253.         log.debug("Config %s loaded: %s", filename, self.__config)
  254.  
  255.     def save(self, filename=None):
  256.         """
  257.         Save configuration to disk
  258.  
  259.         :param filename: if None, uses filename set in object initiliazation
  260.  
  261.         """
  262.         if not filename:
  263.             filename = self.__config_file
  264.         # Check to see if the current config differs from the one on disk
  265.         # We will only write a new config file if there is a difference
  266.         try:
  267.             if self.__config == pickle.load(open(filename, "rb")):
  268.                 # The config has not changed so lets just return
  269.                 self.__save_timer = None
  270.                 return
  271.         except Exception, e:
  272.             log.warning("Unable to open config file: %s", filename)
  273.  
  274.         self.__save_timer = None
  275.  
  276.         # Save the new config and make sure it's written to disk
  277.         try:
  278.             log.debug("Saving new config file %s", filename + ".new")
  279.             f = open(filename + ".new", "wb")
  280.             pickle.dump(self.__config, f)
  281.             f.flush()
  282.             os.fsync(f.fileno())
  283.             f.close()
  284.         except Exception, e:
  285.             log.error("Error writing new config file: %s", e)
  286.             return
  287.  
  288.         # Make a backup of the old config
  289.         try:
  290.             log.debug("Backing up old config file to %s~", filename)
  291.             shutil.move(filename, filename + "~")
  292.         except Exception, e:
  293.             log.error("Error backing up old config..")
  294.  
  295.         # The new config file has been written successfully, so let's move it over
  296.         # the existing one.
  297.         try:
  298.             log.debug("Moving new config file %s to %s..", filename + ".new", filename)
  299.             shutil.move(filename + ".new", filename)
  300.         except Exception, e:
  301.             log.error("Error moving new config file: %s", e)
  302.             return
  303.  
  304.     @prop
  305.     def config():
  306.         """The config dictionary"""
  307.         def fget(self):
  308.             return self.__config
  309.         def fdel(self):
  310.             return self.save()
  311.         return locals()
  312.